#pragma once
namespace graph_virtual
{
   namespace details
   {

   }

   inline virtual_vertex_iterator_t::virtual_vertex_iterator_t(virtual_graph_ptr_t graph)
         :  virtual_graph_(graph)
         ,  bucket_it_(graph->buckets_.begin())
         ,  bucket_end_(graph->buckets_.end())
         ,  graph_it_pair_(graph_basic::vertices(graph->get_bucket(graph->buckets_.begin()->get_inf().id_).get_graph()))
         ,  current_graph_(graph->get_bucket(graph->buckets_.begin()->get_inf().id_).get_graph_ptr())
   {
       //check for empty graph
       for(;graph_it_pair_.first == graph_it_pair_.second && bucket_it_ != bucket_end_; ++bucket_it_)
       {
           current_graph_ = virtual_graph_->get_bucket((*bucket_it_).get_inf().id_).get_graph_ptr();
           graph_it_pair_ = vertices(*current_graph_);
       }
   }

   inline void virtual_vertex_iterator_t::operator ++ ()
   {
       ++graph_it_pair_.first;
       //check for empty graph
       for(;graph_it_pair_.first == graph_it_pair_.second && bucket_it_ != bucket_end_; ++bucket_it_)
       {
           current_graph_ = virtual_graph_->get_bucket((*bucket_it_).get_inf().id_).get_graph_ptr();
           graph_it_pair_ = vertices(*current_graph_);
       }
   }

   inline graph_basic::vertex_t& virtual_vertex_iterator_t::operator * ()
   {
       return *graph_it_pair_.first;
   }
   inline graph_basic::vertex_t const & virtual_vertex_iterator_t::operator * () const
   {
       return *graph_it_pair_.first;
   }
   inline bool virtual_vertex_iterator_t::is_empty() const
   {
       return (bucket_it_ == bucket_end_ && !(graph_it_pair_.first != graph_it_pair_.second));
   }



   
   inline virtual_edge_iterator_t::virtual_edge_iterator_t(virtual_graph_ptr_t graph)
      :  virtual_graph_(graph)
      ,  bucket_it_(graph->buckets_.begin())
      ,  bucket_end_(graph->buckets_.end())
      ,  cur_graph_edge_it_pair_(graph_basic::edges(graph->get_bucket(graph->buckets_.begin()->get_inf().id_).get_graph()))
      ,  current_graph_(graph->get_bucket(graph->buckets_.begin()->get_inf().id_).get_graph_ptr())
   {
      //check for empty graph
       for(;cur_graph_edge_it_pair_.first == cur_graph_edge_it_pair_.second && bucket_it_ != bucket_end_; ++bucket_it_)
       {
           current_graph_ = virtual_graph_->get_bucket((*bucket_it_).get_inf().id_).get_graph_ptr();
           cur_graph_edge_it_pair_ = graph_basic::edges(*current_graph_);
       }
   }


   inline void virtual_edge_iterator_t::operator ++ ()
   {
       ++cur_graph_edge_it_pair_.first;
       for(;cur_graph_edge_it_pair_.first == cur_graph_edge_it_pair_.second && bucket_it_ != bucket_end_; ++bucket_it_)
       {
           current_graph_ = virtual_graph_->get_bucket((*bucket_it_).get_inf().id_).get_graph_ptr();
           cur_graph_edge_it_pair_ = graph_basic::edges(*current_graph_);
       }
   }
   inline bool virtual_edge_iterator_t::is_empty() const
   {
       return (bucket_it_ == bucket_end_ && !(cur_graph_edge_it_pair_.first != cur_graph_edge_it_pair_.second));
   }
   inline graph_basic::edge_t virtual_edge_iterator_t::operator * ()
   {
       return *cur_graph_edge_it_pair_.first;
   }
   inline graph_basic::edge_t const virtual_edge_iterator_t::operator * () const
   {
       return *cur_graph_edge_it_pair_.first;
   }
   
   inline virtual_adjacent_vertices_iterator_t::virtual_adjacent_vertices_iterator_t(graph_basic::vertex_id_t v_id, virtual_graph_t* g)
      :  virtual_graph_(g)
      ,  adj_vert_it_pair_(graph_basic::adj_vertices(v_id, g->get_bucket(v_id.graph_id_).get_graph()))
      ,  source_graph_(g->get_bucket(v_id.graph_id_).get_graph_ptr())
   {}

   inline void virtual_adjacent_vertices_iterator_t::operator ++ ()
   {
       ++adj_vert_it_pair_.first;
   }
   inline graph_basic::vertex_t& virtual_adjacent_vertices_iterator_t::operator * ()
   {
       return *adj_vert_it_pair_.first;
   }
   inline graph_basic::vertex_t const & virtual_adjacent_vertices_iterator_t::operator * () const
   {
       return *adj_vert_it_pair_.first;
   }
   inline bool virtual_adjacent_vertices_iterator_t::is_empty() const
   {
      return !(adj_vert_it_pair_.first != adj_vert_it_pair_.second);
   }
   
   inline virtual_adjacent_edges_iterator_t::virtual_adjacent_edges_iterator_t(graph_basic::vertex_id_t v_id, virtual_graph_t* g)
      :  virtual_graph_(g)
      ,  adj_edges_it_pair_(graph_basic::adj_edges(v_id, g->get_bucket(v_id.graph_id_).get_graph()))
      ,  source_graph_(g->get_bucket(v_id.graph_id_).get_graph_ptr())
{}
   inline void virtual_adjacent_edges_iterator_t::operator ++ ()
   {
       ++adj_edges_it_pair_.first;
   }
   inline graph_basic::edge_t virtual_adjacent_edges_iterator_t::operator * ()
   {
      return *adj_edges_it_pair_.first;
   }
   inline graph_basic::edge_t const virtual_adjacent_edges_iterator_t::operator * () const
   {
      return *adj_edges_it_pair_.first;
   }
   inline bool virtual_adjacent_edges_iterator_t::is_empty() const
   {
       return !(adj_edges_it_pair_.first != adj_edges_it_pair_.second);
   }
   
   inline virtual_vertex_iterator_t vertices(virtual_graph_ptr_t g)
   {
       return virtual_vertex_iterator_t(g);
   }

   inline virtual_edge_iterator_t edges(virtual_graph_ptr_t g)
   {
       return virtual_edge_iterator_t(g);
   }
   inline virtual_adjacent_vertices_iterator_t adjacent_vertices(graph_basic::vertex_id_t id, virtual_graph_ptr_t g)
   {
       return virtual_adjacent_vertices_iterator_t(id, g.get());
   }
   inline virtual_adjacent_edges_iterator_t adjacent_edges(graph_basic::vertex_id_t id, virtual_graph_ptr_t g)
   {
       return virtual_adjacent_edges_iterator_t(id, g.get());
   }

}